/**
 * 用户处理模块
 */
const { validationResult } = require("express-validator");
const { hexHash } = require("../utils/md5");
const uuid = require("../utils/uuid");
const { poolPromise } = require("../db/index");
const token_manager = require("../utils/jwt");
const {
  CODE_OK,
  CODE_BAD_REQUEST,
  CODE_UNAUTHORIZED,
  CODE_Forbidden,
  CODE_Not_Found,
  CODE_Conflict,
  CODE_Internal_Server_Error,
} = require("../config/index");

/**
 * 登录回调
 * @param {*} req
 * @param {*} res
 * @param {*} next
 */
async function login(req, res, next) {
  const validationError = validationResult(req);
  if (!validationError.isEmpty()) {
    return res.status(CODE_BAD_REQUEST).json({
      code: CODE_BAD_REQUEST,
      msg: validationError.errors[0].msg,
      errors: validationError.array(),
      data: null,
    });
  } else {
    try {
      let { username, password } = req.body;
      password = hexHash(password); // 加密
      // console.log(username, password);
      const selectSql = `select id user_id , state from user where username=? and password=?`;
      let [result] = await poolPromise.query(selectSql, [username, password]);
      console.log(result);
      if (!result?.length) {
        return res.status(CODE_BAD_REQUEST).json({
          code: CODE_BAD_REQUEST,
          msg: "用户名或密码错误",
          data: null,
        });
      }
      let { user_id, state } = result[0];
      // 判断用户状态
      if (state === 2) {
        return res.status(CODE_Forbidden).json({
          code: CODE_Forbidden,
          msg: "用户被禁用, 请联系管理员",
          data: null,
        });
      }

      // 生成payload(负载)
      let payload = { user_id };
      // 生成 access_token 访问令牌
      const access_token = token_manager.create_access_token({ ...payload, type: "access" });
      // 生成 refresh_token 刷新令牌
      const jwtid = uuid();
      const refresh_token = token_manager.create_refresh_token(
        { ...payload, type: "refresh" },
        { jwtid }
      );

      // 存储新的refresh_token
      let update_refresh_sql = `update user set refresh_token = ?,jwt_id = ? where id = ?`;
      let [{ affectedRows: refresh_token_rows }] = await poolPromise.query(update_refresh_sql, [
        refresh_token,
        jwtid,
        user_id,
        username,
      ]);
      if (refresh_token_rows === 0) {
        return res.status(CODE_BAD_REQUEST).json({
          code: CODE_BAD_REQUEST,
          msg: "refresh_token存储失败",
          data: null,
        });
      }

      res.status(CODE_OK).json({
        code: CODE_OK,
        msg: "登录成功",
        data: {
          refresh_token,
          access_token,
          user_id,
          username,
        },
      });
    } catch (error) {
      next(error);
    }
  }
}

/**
 * 登出回调
 * @param {*} req
 * @param {*} res
 * @param {*} next
 */
async function logout(req, res, next) {
  try {
    let { user_id } = req.auth;
    const sql = `update user set refresh_token = null,jwt_id = null where id = ?`;
    const [{ affectedRows }] = await poolPromise.execute(sql, [user_id]);
    if (!affectedRows) {
      return res.status(CODE_Internal_Server_Error).json({
        code: CODE_Internal_Server_Error,
        msg: "登出失败",
        data: null,
      });
    }

    res.status(CODE_OK).json({
      code: CODE_OK,
      msg: "登出成功",
    });
  } catch (error) {}
}

/**
 * 注册回调
 * @param {*} req
 * @param {*} res
 * @param {*} next
 */
async function register(req, res, next) {
  // 入参校验
  const validationError = validationResult(req);
  if (!validationError.isEmpty()) {
    // validationError.array() == validationError.errors
    return res.json({
      code: 422,
      msg: validationError.array()[0]?.msg,
      errors: validationError.array(),
      data: null,
    });
  }
  // 校验通过

  let { username, password } = req.body;
  const connection = await poolPromise.getConnection(); // 获取一个连接对象
  try {
    // 查询该账号是否存在
    const select_sql = `select * from user where username = '${username}'`;
    let [result] = await connection.query(select_sql);
    if (result?.length > 0) {
      res.status(CODE_Conflict).json({
        code: CODE_Conflict,
        msg: "用户名已存在,请修改用户名!",
        data: null,
      });
    } else {
      // 不存在则注册
      await connection.beginTransaction(); // 开启事务
      password = hexHash(password); // 加密存储密码
      const insertSql = `insert into user (username,password) values(?,?)`;
      let [{ insertId, affectedRows: user_affectedRows }] = await connection.execute(insertSql, [
        username,
        password,
      ]);
      if (user_affectedRows == 0) {
        await connection.rollback(); // 回滚事务
        res.status(CODE_Internal_Server_Error).json({
          code: CODE_Internal_Server_Error,
          msg: "注册账号失败",
          data: null,
        });
        return;
      }

      // insertId : 此处可以根据插入成功的账号id, 分配默认角色

      await connection.commit(); // 提交事务
      res.status(CODE_OK).json({
        code: CODE_OK,
        msg: "注册成功",
        data: null,
      });
    }
  } catch (error) {
    await connection.rollback(); // 回滚事务
    res.status(CODE_Internal_Server_Error).json({
      code: CODE_Internal_Server_Error,
      msg: "Internal Server Error",
      data: null,
    });
  } finally {
    console.log("释放连接对象");
    connection.release(); // 释放连接对象
  }
}

/**
 * 重置密码
 */
async function resetPassword(req, res, next) {
  const validationError = validationResult(req);
  if (!validationError.isEmpty()) {
    return res.status(CODE_BAD_REQUEST).json({
      code: CODE_BAD_REQUEST,
      msg: validationError.errors[0].msg,
      errors: validationError.array(),
      data: null,
    });
  } else {
    try {
      const { username, oldPassword, newPassword } = req.body;
      const querySql = `select id,username from user where username=? and password=?`;
      // 查询输入的账号密码是否正确
      const [userList] = await poolPromise.query(querySql, [username, hexHash(oldPassword)]);
      if (!userList?.length) {
        return res.status(CODE_BAD_REQUEST).json({
          code: CODE_BAD_REQUEST,
          msg: "用户名或密码错误",
          data: null,
        });
      }
      if (oldPassword == newPassword) {
        return res.status(CODE_BAD_REQUEST).json({
          code: CODE_BAD_REQUEST,
          msg: "新密码和旧密码不能相同!",
          data: null,
        });
      }

      const updateSql = `update user set password=? where username=? and password=?`;
      let [{ affectedRows }] = await poolPromise.query(updateSql, [
        hexHash(newPassword),
        username,
        hexHash(oldPassword),
      ]);
      if (affectedRows == 0) {
        return res.status(CODE_Internal_Server_Error).json({
          code: CODE_Internal_Server_Error,
          msg: "重置密码失败",
          data: null,
        });
      }
      res.status(CODE_OK).json({
        code: CODE_OK,
        msg: "重置密码成功",
        data: null,
      });
    } catch (error) {
      next(error);
    }
  }
}

module.exports = {
  login,
  register,
  logout,
  resetPassword,
};
